/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package yoga.algo.process;

import java.awt.Polygon;
import java.util.ArrayList;
import java.util.Collection;
import yoga.algo.coding.IGenotypeCodec;
import yoga.algo.phenotype.IFitnessCalculator;
import yoga.algo.phenotype.Individual;
import yoga.algo.phenotype.Population;

/**
 *
 * @author Yogev Montekyo
 */
public class GARunner<T>
{
    private Population<T> m_population;
    private IGenotypeCodec<T> m_genotypCodec;
    private MatingScheme<T> m_scheme;
    private int m_currentGenerationNumber = 0;
    private int m_maxNumberOfGenerations = 10000;

    public GARunner(IGenotypeCodec<T> genotypeCodec, MatingScheme<T> scheme)
    {
        m_genotypCodec = genotypeCodec;
        m_scheme = scheme;
        m_population = new Population<T>();
    }

    public void setMaxNumberOfGenerations(int maxNumberOfGenerations)
    {
        m_maxNumberOfGenerations = maxNumberOfGenerations;
    }

    public int getMaxNumberOfGenerations()
    {
        return m_maxNumberOfGenerations;
    }

    public int getCurrentGenerationNumber()
    {
        return m_currentGenerationNumber;
    }

    public IGenotypeCodec<T> getGenotypCodec()
    {
        return m_genotypCodec;
    }

    public MatingScheme<T> getMatingScheme()
    {
        return m_scheme;
    }

    public void addTypesToPopulation(Collection<T> listOfTypes)
    {
        for (T type : listOfTypes)
        {
            Individual<T> individual = new Individual<T>(type, m_genotypCodec);
            m_population.add(individual);
        }
    }

    public void removeAllTypes()
    {
        m_population.removeAll();
    }

    public Population<T> getCurrentPopulation()
    {
        return m_population;
    }

    public boolean nextStep()
    {
        boolean next = false;

        if (m_currentGenerationNumber < m_maxNumberOfGenerations)
        {
            m_population = m_scheme.executeSchemeAndGetNextGeneration(m_population);
            m_currentGenerationNumber++;            
            next = true;
        }

        return next;
    }
    
    public Individual<T> getFittestIndividual()
    {
        ArrayList<Individual<T>> individualList = m_population.toIndividualsList();
        Individual<T> fittestIndividual = null;

        IFitnessCalculator<T> fitnessCalculator = m_scheme.getFitnessCalculator();
        double fittestValueSoFar = fitnessCalculator.getNeutralOrZeroValue();

        for (Individual<T> individual : individualList)
        {
            double currentFitness = fitnessCalculator.getFitnessValue(individual.getPhenotype());
            if (currentFitness >= fittestValueSoFar)
            {
                fittestValueSoFar = currentFitness;
                fittestIndividual = individual;
            }
        }

        return fittestIndividual;
    }

    public Individual<T> getWorstIndividual()
    {
        ArrayList<Individual<T>> individualList = m_population.toIndividualsList();
        Individual<T> fittestIndividual = null;

        IFitnessCalculator<T> fitnessCalculator = m_scheme.getFitnessCalculator();
        double fittestValueSoFar = fitnessCalculator.getMaximumValue();

        for (Individual<T> individual : individualList)
        {
            double currentFitness = fitnessCalculator.getFitnessValue(individual.getPhenotype());
            if (currentFitness <= fittestValueSoFar)
            {
                fittestValueSoFar = currentFitness;
                fittestIndividual = individual;
            }
        }

        return fittestIndividual;
    }

}
